Universo Online
Web Sites Pessoais
Anterior Próximo Índice

Chamando uma Rotina Distante a partir do Turbo C

O modelo "default" de memória do Turbo C é o SMALL, ou seja, este é modelo usado quando não é feita nenhuma opção explícita pelo programador, seja no Ambiente Integrado ou na linha de comando. Na linha de comando você pode usar, antes do nome do programa a ser compilado, o tipo de modelo a ser usado (TINY é -mt, SMALL é -ms, LARGE é -ml e assim por diante). Nos modelos maiores de memória, como LARGE, o processador, antes de chamar a rotina, empilha os valores CS:IP do programa chamador. Lembre-se, IP é sempre o endereço da próxima instrução, ou seja, quando o processador está executando um instrução, o valor de IP já não contém o endereço dessa instrução que está sendo executada, mas o endereço da próxima instrução. Nesse caso, quando o processador encontra um RETF no final do procedimento, ele retira CS:IP da pilha como se fizesse um POP IP e um POP CS, fazendo com que CS:IP sejam atualizados com os valores antigos, e salta para o endereço distante CS:IP, que é exatamente o endereço imediatamente após a instrução de chamada (CALL, em assembly). Uma chamada distante em C não difere em nada de uma chamada distante em Pascal: ambas colocam os dois bytes extras de CS na pilha; portanto, o valor final de SP, após empilhar BP dentro do procedimento, vai ter 2 bytes a mais, e a aritmética da pilha muda levemente:


SP        Valor inicial do Ponteiro de Pilha
SP - 02   Valor de SP após empilhar o último parâmetro (o terceiro)
SP - 04   Valor de SP após empilhar o penúltimo parâmetro (o segundo)
SP - 06   Valor de SP após empilhar o  primeiro parâmetro
SP - 08   Valor de SP após empilhar o valor de CS
SP - 10   Valor de SP após empilhar o valor de IP
SP - 12   Valor de SP após empilhar o valor de BP dentro da rotina
Considerando o valor final de SP acima (SP Inicial menos 12), os endereços dos parâmetros dentro da pilha podem ser acessados usando este método (após um MOV BP, SP):
1° parâmetro = [BP+06] = [(SP - 12) + 06] = [SP - 6]
2° parâmetro = [BP+08] = [(SP - 12) + 08] = [SP - 4]
3° parâmetro = [BP+10] = [(SP -12)  + 10] = [SP - 2]
  
Os números não mentem: os endereços obtidos acima correspondem exatamente aos deslocamentos dos argumentos no segmento de pilha, como você pode constatar comparando com a configuração anterior. Veja abaixo um exemplo de uma rotina em NASM e um programa usando Turbo. A rotina recebe como parâmetro um único argumento (um ponteiro para um string de caracteres), e exibe o string usando a interrupção 0x21 do DOS, serviço 0x02, que imprime um único caracter passado usando o registrador DL. Note que ele é o primeiro e único parâmetro:
			
    GLOBAL _prints

segment printsf_TEXT public class=CODE align=1

_prints:
        push   bp
        mov    bp,sp
        push   si
        push   ds
        mov    ah,2
        lds    si,[bp+6]
        cld
    .1:

        lodsb
        cmp al,0
        je .fim
        mov dl,al
        int 0x21
        jmp short .1
     .fim:
        pop    ds
        pop    si
        pop    bp
        retf 



/* programa FAR.C  */
/* chamada de rotina distante para modelo largo de memoria */
/* ------------------------------------
   Use:
        nasm -fobj printsf.asm

   para produzir printsf.obj e depois use

        tcc -ml far.c printsf.obj

   para produzir far.exe. A opcao -ml significa
   model large (modelo grande de memoria)
---------------------------------------- */

extern void prints(char *);


int main()
{
  prints("Testando o modelo grande de memoria com NASM e Turbo C...");
  return(0);
}


/*  você também pode chamar uma rotina distante em modelo pequeno */
/* nesse caso, use far no tipo de retorno e nos argumentos do tipo matriz */
/* Exemplo de chamada de rotina distante para modelo SMALL de memoria */
/* ------------------------------------
   Use:
        nasm -fobj printsf.asm

   para produzir printsf.obj e depois use

        tcc  far.c printsf.obj

   
---------------------------------------- */

extern void far prints(char far *);


int main()
{
  prints("Testando rotina distante com modelo SMALL de memória...");
  return(0);
}




Anterior Próximo Índice